﻿Imports BoneSoft.CSS
Imports System.IO
Imports System.Text.RegularExpressions

Namespace Css
    Friend Class CssFile
        Private _doc As CSSDocument
        Private _parser As CSSParser
        Private _name As String
        Friend Sub New(ByVal Name As String, Optional ByVal LoadDefault As Boolean = False)
            _parser = New CSSParser
            Dim css As String = String.Empty
            If LoadDefault Then
                css = File.ReadAllText(Toolbox.DefaultStylesPath & Name)
            Else
                css = File.ReadAllText(Toolbox.StylesPath & Name)
            End If
            _doc = _parser.ParseText(css)
            UpdateImages()
            _name = Name
        End Sub
        Private Sub UpdateImages()
            _doc = _parser.ParseText(_doc.ToString.Replace("../Images/", Toolbox.CssImageDir).Replace("../images/", Toolbox.CssImageDir))
        End Sub
        Private Sub RevertImages()
            _doc = _parser.ParseText(_doc.ToString.Replace(Toolbox.CssImageDir, "../Images/"))
        End Sub
        Friend Sub SetCssValue(ByVal SelectorName As String, ByVal Declaration As String, ByVal Value As String, Optional ByVal termID As Integer = 0)
            Dim t As Term = GetTerm(SelectorName, Declaration, termID)
            If t.Type = TermType.Url Then
                t.Value = Regex.Replace(Value, "url\(\'(?<url>.*)\'\)", "${url}")
            ElseIf t.Type = TermType.Number Then
                Value = Value.Replace("px", "")
                Select Case t.Unit
                    Case BoneSoft.CSS.Unit.PX
                        t.Value = Value
                    Case BoneSoft.CSS.Unit.PT
                        t.Value = Value
                    Case Else
                        Try
                            Value = Int32.Parse(Value)
                            t.Value = Value & "px"
                        Catch ex As Exception
                            t.Value = Value
                        End Try
                End Select
            Else
                t.Value = Value
            End If
        End Sub
        Private Function GetTerm(ByVal SelectorName As String, ByVal Declaration As String, ByVal TermID As Integer) As Term
            Dim explist As List(Of Expression) = (From rs As RuleSet In _doc.RuleSets From s As Selector In rs.Selectors From d As Declaration In rs.Declarations Where s.ToString = SelectorName AndAlso d.Name = Declaration Select d.Expression).ToList
            If explist.Count = 0 Then
                Dim rulesets As List(Of RuleSet) = (From rs As RuleSet In _doc.RuleSets From s As Selector In rs.Selectors Where s.ToString = SelectorName Select rs).ToList
                Dim newrs As RuleSet
                Dim sel As Selector
                Dim ss As New SimpleSelector
                If rulesets.Count = 0 Then
                    newrs = New RuleSet
                    sel = New Selector
                    ss = New SimpleSelector
                    Select Case SelectorName.Substring(0, 1)
                        Case "#"
                            ss.ID = SelectorName.Remove(0, 1)
                        Case "."
                            ss.Class = SelectorName.Remove(0, 1)
                        Case Else
                            ss.ElementName = SelectorName
                    End Select
                    _doc.RuleSets.Add(newrs)
                    newrs.Selectors.Add(sel)
                    sel.SimpleSelectors.Add(ss)
                Else
                    newrs = rulesets(0)
                End If

                Dim dec As New Declaration
                Dim exp As New Expression
                Dim t As New Term

                newrs.Declarations.Add(dec)
                exp.Terms.Add(t)
                dec.Name = Declaration
                dec.Expression = exp
                Return t
            Else
                Return explist(0).Terms(TermID)
            End If
        End Function
        Friend Function GetCssValue(ByVal SelectorName As String, ByVal Declaration As String, Optional ByVal TermId As Integer = 0) As Term
            Dim explist As List(Of Expression) = (From rs As RuleSet In _doc.RuleSets From s As Selector In rs.Selectors From d As Declaration In rs.Declarations Where s.ToString = SelectorName AndAlso d.Name = Declaration Select d.Expression).ToList
            If explist.Count > 0 Then
                If explist(0).Terms.Count > TermId Then
                    Return explist(0).Terms(TermId)
                End If
            End If
            Return Nothing
        End Function
        Friend Function GetCssColorValue(ByVal SelectorName As String, ByVal Declaration As String, Optional ByVal TermId As Integer = 0) As Color
            Dim explist As List(Of Expression) = (From rs As RuleSet In _doc.RuleSets From s As Selector In rs.Selectors From d As Declaration In rs.Declarations Where s.ToString = SelectorName AndAlso d.Name = Declaration Select d.Expression).ToList
            If explist.Count > 0 Then
                If explist(0).Terms.Count > TermId Then
                    If explist(0).Terms(TermId).IsColor = False Then
                        Return ColorTranslator.FromHtml(explist(0).Terms(TermId).Value)
                    Else
                        Return explist(0).Terms(TermId).ToColor()
                    End If
                End If
            End If
            Return Nothing
        End Function
        Friend Sub RemoveCssValue(ByVal SelectorName As String, ByVal Declaration As String, ByVal Value As String)
            Dim terms As List(Of Term) = (From rs As RuleSet In _doc.RuleSets From s As Selector In rs.Selectors From d As Declaration In rs.Declarations From t As Term In d.Expression.Terms Where s.ToString = SelectorName AndAlso d.Name = Declaration AndAlso t.Value = Value Select t).Distinct.ToList
            For Each t As Term In terms
                Dim dec As Declaration = GetTermParent(t)
                If dec.Expression.Terms.Count = 1 Then
                    GetDeclarationParent(dec).Declarations.Remove(dec)
                Else
                    dec.Expression.Terms.Remove(t)
                End If
            Next
        End Sub
        Private Function GetTermParent(ByVal Term As Term) As Declaration
            Dim l As List(Of Declaration) = (From rs As RuleSet In _doc.RuleSets From d As Declaration In rs.Declarations From t As Term In d.Expression.Terms Where t Is Term Select d).ToList
            Return l(0)
        End Function
        Private Function GetDeclarationParent(ByVal Declaration As Declaration) As RuleSet
            Dim l As List(Of RuleSet) = (From rs As RuleSet In _doc.RuleSets From d As Declaration In rs.Declarations Where d Is Declaration Select rs).ToList
            Return l(0)
        End Function
        Friend ReadOnly Property Text As String
            Get
                Return _doc.ToString()
            End Get
        End Property
        Friend ReadOnly Property Name As String
            Get
                Return _name
            End Get
        End Property
        Friend ReadOnly Property DefaultFile As CssFile
            Get
                Return New CssFile(Name, True)
            End Get
        End Property
        Friend Sub ReplaceImages(Path As String)
            Path = Path.Replace("\", "/")
            Dim explist As List(Of Term) = (From rs As RuleSet In _doc.RuleSets From d As Declaration In rs.Declarations From t As Term In d.Expression.Terms Where t.Type = TermType.Url AndAlso t.Value.ToLower.Contains(Path.ToLower) Select t).ToList
            For Each Term As Term In explist
                Term.Value = Term.Value & "?guid=" & Guid.NewGuid.ToString
                Term.Value = Regex.Replace(Term.Value, "\?guid=.*\?guid=", "?guid=")
            Next
        End Sub
        Friend Sub Save()
            RevertImages()
            'Fix a parser bug
            Dim towrite As String = _doc.ToString
            towrite = Regex.Replace(towrite, "(?<digit>\d)\.+\s(?<digit2>\d)em", "${digit}.${digit2}em")

            File.WriteAllText(Toolbox.TempPath & My.Settings.StylesPath & Name, towrite)
            UpdateImages()
        End Sub
    End Class
End Namespace